//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT||LIC==GOOGLE

/**
 * @addtogroup FXCRT
 * @{
 */

/**
 * @file
 * @brief Memory management.
 *
 *
 * FPDFAPI may be using different heap as the application (in case of DLL version of FPDFAPI),
 * therefore, the application should use the following memory allocation and free functions
 * in order to exchange pointers between the API and application.
 *
 *
 * There are two layers of memory manager in FOXIT API:
 *
 *	1. System level memory manager. This level is system dependant.
 *		The API provides a default system memory manager (which uses CRT malloc/free functions),
 *		but application can implement their own manager to cater to different system environment.
 *
 *	2. Foxit memory manager. This level is system independant, but it relies on a system level manager.
 *		The API provides a default Foxit memory manager, which relies on the default system manager.
 *		Applications can not customize the Foxit memory manager, but they can create different
 *		Foxit memory manager instance, that rely on different underlying system manager
 *		(for example, each system manager may use a different heap, then, different Foxit manager
 *		will be able to use separate heaps.)
 *
 *
 *	Foxit memory manager also provide sub-heap feature for aggregating objects together to
 *	avoid memory fragmentation.
 */

//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FX_MEMORY_H_
#define _FX_MEMORY_H_
 
#ifndef _FX_SYSTEM_H_
	#include "fx_system.h"
#endif
//<<<+++OPENSOURCE_MUST_END

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT

/** @brief Flag for no calling OOM-handler when memory allocation failed. */
#define FXMEM_NONLEAVE			1
/** @brief Flag for allocate movable memory. */
#define FXMEM_MOVABLE			2
/** @brief Flag for allocate discardable memory. */
#define FXMEM_DISCARDABLE		4

// Base memory routines
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief System level memory manager. Application can implement their own system memory manager.
 */
typedef struct _FXMEM_SystemMgr {
	/**
	 * A pointer type to an allocation function.
	 *
	 * The function prototype is:
	 *		void* Alloc(FXMEM_SystemMgr* pMgr, size_t size, int flags);
	 * @param[in] pMgr	A pointer to a FXMEM_SystemMgr object.
	 * @param[in] size	The size in bytes to allocate.
	 * @param[in] flags	Memory allocation attributes.
	 * @return Address of new memory block.
	 */
	void* (*Alloc)(struct _FXMEM_SystemMgr* pMgr, size_t size, int flags);
	/**
	 * A pointer type to a debug-mode allocation function.
	 *
	 * The function prototype is:
	 *		void* AllocDebug(FXMEM_SystemMgr* pMgr, size_t size, int flags, FX_LPCSTR file, int line);
	 * @param[in] pMgr	A pointer to a FXMEM_SystemMgr object.
	 * @param[in] size	The size in bytes to allocate.
	 * @param[in] flags	Memory allocation attributes.
	 * @param[in] file	The name of the current source file.
	 * @param[in] line	The line number in the current source file.
	 * @return Address of new memory block.
	 */
	void* (*AllocDebug)(struct _FXMEM_SystemMgr* pMgr, size_t size, int flags, FX_LPCSTR file, int line);
	/**
	 * A pointer type to a reallocation function.
	 * 
	 * The function prototype is:
	 *		void* Realloc(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 * @param[in] pointer	A pointer to a memory block.
	 * @param[in] size		The size in bytes to reallocate.
	 * @param[in] flags		Memory allocation attributes.
	 * @return Address of new memory block.
	 */
	void* (*Realloc)(struct _FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags);
	/**
	 * A pointer type to a debug-mode reallocation function.
	 * 
	 * The function prototype is:
	 *		void ReallocDebug(FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags, FX_LPCSTR file, int line);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 * @param[in] pointer	A pointer to a memory block.
	 * @param[in] size		The size in bytes to reallocate.
	 * @param[in] flags		Memory allocation attributes.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 * @return Address of new memory block.
	 */
	void* (*ReallocDebug)(struct _FXMEM_SystemMgr* pMgr, void* pointer, size_t size, int flags, FX_LPCSTR file, int line);
	/**
	 * A pointer type to a lock function.
	 * 
	 * The function prototype is:
	 *		void Lock(FXMEM_SystemMgr* pMgr, void* handle);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 * @param[in] handle	A handle to a memory block.
	 * @return a pointer to the locked memory block.
	*/
	void* (*Lock)(struct _FXMEM_SystemMgr* pMgr, void* handle);
	/**
	 * A pointer type to a unlock function.
	 * 
	 * The function prototype is:
	 *		void Unlock(FXMEM_SystemMgr* pMgr, void* handle);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 * @param[in] handle	a handle to a memory block.
	 */
	void  (*Unlock)(struct _FXMEM_SystemMgr* pMgr, void* handle);
	/**
	 * A pointer type to a free function.
	 * 
	 * The function prototype is:
	 *		void Free(FXMEM_SystemMgr* pMgr, void* pointer, int flags);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 * @param[in] pointer	A pointer to a memory block.
	 * @param[in] flags		Memory allocation attributes.
	 */
	void  (*Free)(struct _FXMEM_SystemMgr* pMgr, void* pointer, int flags);
	/**
	 * A pointer type to a purge function, which can be used to purge excessive memory without
	 * touching any used memory.
	 * 
	 * The function prototype is:
	 *		void Purge(FXMEM_SystemMgr* pMgr);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 */
	void  (*Purge)(struct _FXMEM_SystemMgr* pMgr);
	/**
	 * A pointer type to a memory-collection function.
	 * 
	 * The function prototype is:
	 *		void CollectAll(FXMEM_SystemMgr* pMgr);
	 * @param[in] pMgr		A pointer to a FXMEM_SystemMgr object.
	 */
	void  (*CollectAll)(struct _FXMEM_SystemMgr* pMgr);
	
	/** A generic typeless pointer for user data. */
	void* user;
} FXMEM_SystemMgr;

/**
 * @brief Foxit memory manager.
 * 
 * Application can create different instances; Data members are hidden.
 */
FX_DEFINEHANDLE(FXMEM_FoxitMgr)

/**
 * Create a Foxit manager. A system manager must be provided for actual allocation.
 *
 * On desktop platforms, you don't have to create a Foxit manager to use memory allocation, 
 * because FPDFAPI comes with a default Foxit manager (and underlying default system manager).
 *
 * But if your application uses non-default system manager, you will have to create a
 * new Foxit manager that makes use of the custom system manager.
 *
 * @param[in] pSystemMgr	A pointer to a FXMEM_SystemMgr object.
 * @return A pointer to a FXMEM_FoxitMgr object.
*/
FXMEM_FoxitMgr*	FXMEM_CreateFoxitMgr(FXMEM_SystemMgr* pSystemMgr);

/**
 * @brief Fixed memory manager.
 */
typedef struct _FXMEM_SystemMgr2
{
	/**
	 * Called when fixed memory manager needs more memory.
	 * 
	 * @param[in] pMgr			A pointer to a FXMEM_SystemMgr2 object.
	 * @param[in] alloc_size	The size that API is trying to allocate.
	 * @param[out] new_memory	It receives the newly allocated memory.
	 * @param[out] new_size		It receives the newly allocated size. The newly allocated size should be at least alloc_size + 32.
	 * @return Nonzero if the function is successful; otherwise 0.
	 */
	FX_BOOL	(*More)(struct _FXMEM_SystemMgr2* pMgr, size_t alloc_size, void** new_memory, size_t* new_size);
	/**
	 * Called when an addition memory pool becomes empty.
	 * 
	 * @param[in] pMgr			A pointer to a FXMEM_SystemMgr2 object.
	 * @param[in] memory		A pointer to a memory block.
	 */
	void	(*Free)(struct _FXMEM_SystemMgr2* pMgr, void* memory);
} FXMEM_SystemMgr2;

/**
 * Create a Foxit manager from a pre-allocated, fixed memory buffer.
 * 
 * This form of Foxit manager is typically used on embedded systems where memory
 * is limited and can be dedicated to single task. The application is responsible
 * to allocate and free the fixed memory buffer.
 * 
 * Buffer size can't be lower than 512KB, there is no upper limit.
 * 
 * Now the fixed memory manager supports extensible pool. If pExtender is not NULL, then
 * when current memory pool runs out, it will ask for more from the system.
 * 
 * @param[in] pMemory		A pointer to a memory block.
 * @param[in] size			The size in bytes of the memory block pointed by 'pMemory'.
 * @param[in] pExtender		A pointer to a FXMEM_SystemMgr2 object.
 * @return A pointer to a FXMEM_FoxitMgr object.
*/
FXMEM_FoxitMgr*	FXMEM_CreateFixedMgr(void* pMemory, size_t size, FXMEM_SystemMgr2* pExtender);

/**
 * @brief	Create a fixed memory manager as default implementation.
 *
 * @param[in]size			Initial size of memory pool, in bytes. It should be not less than 8MB(1024 * 1024 * 8).
 * @param[in]extensible		If it's <b>TRUE</b>, memory pool will extend if need more space. <b>FALSE</b> means memory cannot be extended.
 *
 * @return	A pointer to a FXMEM_FoxitMgr object.
 *
 * @remark	If <i>extensible</i> is <b>FALSE</b> and there is no enough space to allocate, <b>FX_Alloc</b> or <b>FX_Realloc</b> will return <b>NULL</b> directly.
 *			For extensible memory manager, it will try to request more memory pools to allocate.
 */
FXMEM_FoxitMgr* FXMEM_CreateMemoryMgr(size_t size, FX_BOOL extensible);

/**
 * @brief	Get the size of a memory block to which <i>ptr</i> points.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object, it should be created as fixed memory manager.
 * @param[in] ptr			A pointer to a memory block.
 *
 * @return	Memory block size in bytes if <i>ptr</i> locates in fixed memory manager, or 0 returns.
 */
size_t FXMEM_GetBlockSizeInFixedMgr(FXMEM_FoxitMgr* pFoxitMgr, void* ptr);

/**
 * Get default memory manager for current module.
 *
 * @return The default FXMEM_FoxitMgr pointer.
 */
FXMEM_FoxitMgr* FXMEM_GetDefaultMgr();

/**
 * Set default Foxit manager for current compile module (EXE, DLL, etc.).
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 */
void	FXMEM_SetDefaultMgr(FXMEM_FoxitMgr* pFoxitMgr);

/**
 * Destroy a Foxit manager instance. If the platform supports auto-collection,
 * then all allocated memory blocks will be released.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 */
void	FXMEM_DestroyFoxitMgr(FXMEM_FoxitMgr* pFoxitMgr);

/**
 * @name Basic memory operations
 */
 /*@{*/

/**
 * Foxit basic memory allocation function.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] size			The size in bytes to allocate.
 * @param[in] flags			Memory allocation attributes.
 * @return Address of new memory block.
 */
void*	FXMEM_Alloc(FXMEM_FoxitMgr* pFoxitMgr, size_t size, int flags);
/**
 * Foxit basic memory allocation function in debug-mode.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] size			The size in bytes to allocate.
 * @param[in] flags			Memory allocation attributes.
 * @param[in] file			The name of the current source file.
 * @param[in] line			The line number in the current source file.
 * @return Address of new memory block.
 */
void*	FXMEM_AllocDebug(FXMEM_FoxitMgr* pFoxitMgr, size_t size, int flags, FX_LPCSTR file, int line);
/**
 * Foxit basic memory reallocation function.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] pointer		A pointer to a memory block.
 * @param[in] new_size		The size in bytes to reallocate.
 * @param[in] flags			Memory allocation attributes.
 * @return Address of new memory block.
 */
void*	FXMEM_Realloc(FXMEM_FoxitMgr* pFoxitMgr, void* pointer, size_t new_size, int flags);
/**
 * Foxit basic memory reallocation function in debug-mode.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] pointer		A pointer to a memory block.
 * @param[in] new_size		The size in bytes to reallocate.
 * @param[in] flags			Memory allocation attributes.
 * @param[in] file			The name of the current source file.
 * @param[in] line			The line number in the current source file.
 * @return Address of new memory block.
 */
void*	FXMEM_ReallocDebug(FXMEM_FoxitMgr* pFoxitMgr, void* pointer, size_t new_size, int flags, FX_LPCSTR file, int line);
/**
 * Foxit basic memory free function.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] pointer		A pointer to a memory block.
 * @param[in] flags			Memory allocation attributes.
 */
void	FXMEM_Free(FXMEM_FoxitMgr* pFoxitMgr, void* pointer, int flags);

/*@}*/

/**
 * Release all excessive memory without touching any used memory.
 * This is useful for extensible fixed memory manager (FXMEM_SystemMgr2),
 * because we never free those additional memory pool until the memory manager destroyed.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
*/
void	FXMEM_PurgeMgr(FXMEM_FoxitMgr* pFoxitMgr);

/**
 * Report Out-of-memory (OOM).
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 */
void	FXMEM_ReportOOM(FXMEM_FoxitMgr* pFoxitMgr);

/**
 * @brief Memory debugger interface. All functions must be implemented.
 */
typedef struct {
	/**
	 * A pointer type to an allocation-callback function.
	 *
	 * The function prototype is:
	 *		void OnAlloc(FXMEM_FoxitMgr* pMgr, void* p, size_t size, int flags);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] p			Address of the allocated memory block.
	 * @param[in] size		The size in bytes allocated.
	 * @param[in] flags		Memory allocation attributes.
	 */
	void	(*OnAlloc)(FXMEM_FoxitMgr* pMgr, void* p, size_t size, int flags);
	/**
	 * A pointer type to a debug-mode allocation-callback function.
	 *
	 * The function prototype is:
	 *		void OnAllocDebug(FXMEM_FoxitMgr* pMgr, void* p, size_t size, int flags, FX_LPCSTR file, int line);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] p			Address of the allocated memory block.
	 * @param[in] size		The size in bytes allocated.
	 * @param[in] flags		Memory allocation attributes.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 */
	void	(*OnAllocDebug)(FXMEM_FoxitMgr* pMgr, void* p, size_t size, int flags, FX_LPCSTR file, int line);
	/**
	 * A pointer type to a reallocation-callback function.
	 * 
	 * The function prototype is:
	 *		void OnRealloc(FXMEM_FoxitMgr* pMgr, void* old_p, void* new_p, size_t size, int flags);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] old_p		Address of the old memory block.
	 * @param[in] new_p		Address of the new memory block.
	 * @param[in] size		The size in bytes reallocated.
	 * @param[in] flags		Memory allocation attributes.
	 */
	void	(*OnRealloc)(FXMEM_FoxitMgr* pMgr, void* old_p, void* new_p, size_t size, int flags);
	/**
	 * A pointer type to a debug-mode reallocation-callback function.
	 * 
	 * The function prototype is:
	 *		void OnReallocDebug(FXMEM_FoxitMgr* pMgr, void* old_p, void* new_p, size_t size, int flags, FX_LPCSTR file, int line);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] old_p		Address of the old memory block.
	 * @param[in] new_p		Address of the new memory block.
	 * @param[in] size		The size in bytes reallocated.
	 * @param[in] flags		Memory allocation attributes.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 */
	void	(*OnReallocDebug)(FXMEM_FoxitMgr* pMgr, void* old_p, void* new_p, size_t size, int flags, FX_LPCSTR file, int line);
	/**
	 * A pointer type to a free-callback function.
	 *
	 * The function prototype is:
	 *		void OnFree(FXMEM_FoxitMgr* pMgr, void* p, int flags);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] p			Address of the memory block to be freed.
	 * @param[in] flags		Memory allocation attributes.
	 */
	void	(*OnFree)(FXMEM_FoxitMgr* pMgr, void* p, int flags);
	/**
	 * A pointer type to a tag-callback function.
	 *
	 * The function prototype is:
	 *		void OnTag(FXMEM_FoxitMgr* pMgr, FX_LPCSTR tag);
	 * @param[in] pMgr		A pointer to a FXMEM_FoxitMgr object.
	 * @param[in] tag		Tag string.
	 */
	void	(*OnTag)(FXMEM_FoxitMgr* pMgr, FX_LPCSTR tag);
} FXMEM_Debugger;

/**
 * Use a memory debugger which capturing all memory activities. Use NULL for pDebugger parameter to stop debugging.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object to be debugged.
 * @param[in] pDebugger		A pointer to a FXMEM_Debugger object.
 */
void	FXMEM_UseDebugger(FXMEM_FoxitMgr* pFoxitMgr, FXMEM_Debugger* pDebugger);

/**
 * Output a memory debug tag.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] tag			Tag string.
 */
void	FXMEM_OutputDebugTag(FXMEM_FoxitMgr* pFoxitMgr, FX_LPCSTR tag);

/**
 * @brief the prototype of the Out-Of-Memory handler.
 *
 * @param[in] pFoxitMgr		A pointer to a FXMEM_FoxitMgr object.
 * @param[in] param			A generic typeless pointer for user data.
 */
typedef void (*FPDF_OOM_Handler)(FXMEM_FoxitMgr* pFoxitMgr, void* param);

/**
 * Setup A Out-Of-Memory handler for a Foxit memory manager.
 *
 * @param[in] pFoxitMgr			A pointer to a FXMEM_FoxitMgr object.
 * @param[in] pOOMReportFunc	A pointer a Out-Of-Memory handler.
 * @param[in] param				A generic typeless pointer for user data to be called back.
 */
void	FXMEM_SetOOMHandler(FXMEM_FoxitMgr* pFoxitMgr, FPDF_OOM_Handler pOOMReportFunc, void* param);

/**
	* @name Following base memory functions use default Foxit manager for current module
	*/
	/*@{*/

/**
	* Default allocation function using default Foxit memory manager for current module.
	*
	* @param[in] byte_size		The size in bytes to allocate.
	* @param[in] flags			Memory allocation attributes.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultAlloc(size_t byte_size, int flags);
/**
	* Default allocation function using default Foxit memory manager for current module.
	*
	* @param[in] units			Number of units to allocate.
	* @param[in] unit_size		The byte size of each unit.
	* @param[in] flags			Memory allocation attributes.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultAlloc2(size_t units, size_t unit_size, int flags);
/**
	* Default debug-mode allocation function using default Foxit memory manager for current module.
	*
	* @param[in] size			The size in bytes to allocate.
	* @param[in] flags			Memory allocation attributes.
	* @param[in] file			The name of the current source file.
	* @param[in] line			The line number in the current source file.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultAllocDebug(size_t size, int flags, FX_LPCSTR file, int line);
/**
	* Default debug-mode allocation function using default Foxit memory manager for current module.
	*
	* @param[in] units			Number of units to allocate.
	* @param[in] unit_size		The byte size of each unit.
	* @param[in] flags			Memory allocation attributes.
	* @param[in] file			The name of the current source file.
	* @param[in] line			The line number in the current source file.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultAllocDebug2(size_t units, size_t unit_size, int flags, FX_LPCSTR file, int line);
/**
	* Default reallocation function using default Foxit memory manager for current module.
	*
	* @param[in] pointer		Address of the memory block to be reallocated.
	* @param[in] new_size		The new size in bytes to reallocate.
	* @param[in] flags			Memory allocation attributes.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultRealloc(void* pointer, size_t new_size, int flags);
/**
	* Default reallocation function using default Foxit memory manager for current module.
	*
	* @param[in] pointer		Address of the memory block to be reallocated.
	* @param[in] units			Number of units to allocate.
	* @param[in] unit_size		The byte size of each unit.
	* @param[in] flags			Memory allocation attributes.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultRealloc2(void* pointer, size_t units, size_t unit_size, int flags);
/**
	* Default debug-mode reallocation function using default Foxit memory manager for current module.
	*
	* @param[in] pointer		Address of the memory block to be reallocated.
	* @param[in] new_size		The new size in bytes to reallocate.
	* @param[in] flags			Memory allocation attributes.
	* @param[in] file			The name of the current source file.
	* @param[in] line			The line number in the current source file.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultReallocDebug(void* pointer, size_t new_size, int flags, FX_LPCSTR file, int line);
/**
	* Default debug-mode reallocation function using default Foxit memory manager for current module.
	*
	* @param[in] pointer		Address of the memory block to be reallocated.
	* @param[in] units			Number of units to allocate.
	* @param[in] unit_size		The byte size of each unit.
	* @param[in] flags			Memory allocation attributes.
	* @param[in] file			The name of the current source file.
	* @param[in] line			The line number in the current source file.
	* @return Address of new memory block.
	*/
void*	FXMEM_DefaultReallocDebug2(void* pointer, size_t units, size_t unit_size, int flags, FX_LPCSTR file, int line);
/**
	* Default free function using default Foxit memory manager for current module.
	*
	* @param[in] pointer		Address of a memory block.
	* @param[in] flags			Memory allocation attributes.
	*/
void	FXMEM_DefaultFree(void* pointer, int flags);

/*@}*/

/* FPDFAPI applications should use the FX_Alloc macro for non-class data types */
#ifdef _DEBUG
	#define FX_Alloc(type, size) (type*)FXMEM_DefaultAllocDebug2(size, sizeof(type), 0, __FILE__, __LINE__)
	#define FX_Realloc(type, ptr, new_size) (type*)FXMEM_DefaultReallocDebug2(ptr, new_size, sizeof(type), 0, __FILE__, __LINE__)
#else
	/**
		* @brief A macro for Foxit memory allocation operation.
		* @hideinitializer
		*/
	#define FX_Alloc(type, size) (type*)FXMEM_DefaultAlloc2(size, sizeof(type), 0)
	/**
		* @brief A macro for Foxit memory reallocation operation.
		* @hideinitializer
		*/
	#define FX_Realloc(type, ptr, size) (type*)FXMEM_DefaultRealloc2(ptr, size, sizeof(type), 0)
#endif

#ifdef _DEBUG
	#define FX_AllocNL(type, size) (type*)FXMEM_DefaultAllocDebug2(size, sizeof(type), FXMEM_NONLEAVE, __FILE__, __LINE__)
	#define FX_ReallocNL(type, ptr, new_size) (type*)FXMEM_DefaultReallocDebug2(ptr, new_size, sizeof(type), FXMEM_NONLEAVE, __FILE__, __LINE__)
#else
	/**
		* @brief A macro for Foxit memory allocation operation with non-leaving (return NULL if OOM).
		* @hideinitializer
		*/
	#define FX_AllocNL(type, size) (type*)FXMEM_DefaultAlloc2(size, sizeof(type), FXMEM_NONLEAVE)
	/**
		* @brief A macro for Foxit memory reallocation operation with non-leaving (return NULL if OOM).
		* @hideinitializer
		*/
	#define FX_ReallocNL(type, ptr, size) (type*)FXMEM_DefaultRealloc2(ptr, size, sizeof(type), FXMEM_NONLEAVE)
#endif

/** @brief A macro for Foxit memory free operation. */
#define FX_Free(pointer) FXMEM_DefaultFree(pointer, 0)

#ifdef __cplusplus
}
#endif

#ifdef __cplusplus

/**
 * @brief BASE CLASS FOR (ALMOST) ALL OTHER CLASSES IN FPDFAPI.
 *
 * This class is created for centralizing memory management.
 * It uses default memory manager to allocator and free memory, if your module uses 
 * a separate memory manager, you will need to derive your class from CFX_AllocObject.
 */
class CFX_Object
{
public:
	/**
	 * new operator for debug mode.
	 *
	 * @param[in] size		The size in bytes to allocate.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 * @return Address of a new memory block.
	 */
	void*			operator new (size_t size, FX_LPCSTR file, int line);
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator for debug mode.
	 *
	 * @param[in] p			The Address of a memory block to be deleted.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 */
	void			operator delete (void* p, FX_LPCSTR file, int line);
#endif

	/**
	 * new operator for release mode.
	 *
	 * @param[in] size		The size in bytes to allocate.
	 * @return Address of a new memory block.
	 */
	void*			operator new (size_t size);
	/**
	 * delete operator for release mode.
	 *
	 * @param[in] p			The Address of a memory block to be deleted.
	 */
	void			operator delete (void* p);

	/**
	 * new operator of vector for debug mode.
	 *
	 * @param[in] size		The size in bytes to allocate.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 * @return Address of a new memory block.
	 */
	void*			operator new[] (size_t size, FX_LPCSTR file, int line);
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator of vector for debug mode.
	 *
	 * @param[in] p			The Address of a memory block to be deleted.
	 * @param[in] file		The name of the current source file.
	 * @param[in] line		The line number in the current source file.
	 */
	void			operator delete[] (void* p, FX_LPCSTR file, int line);
#endif

	/**
	 * new operator of vector for non-debug mode.
	 *
	 * @param[in] size		The size in bytes to allocate.
	 * @return Address of a new memory block.
	 */
	void*			operator new[] (size_t size);
	/**
	 * delete operator of vector for non-debug mode.
	 *
	 * @param[in] p			The Address of a memory block to be deleted.
	 */
	void			operator delete[] (void* p);

	/**
	 * placement new operator.
	 */
	void*			operator new (size_t, void* buf) { return buf; }
#ifndef _FX_NO_EXCEPTION_
	/**
	 * placement delete operator.
	 */
	void			operator delete (void*, void*) {}
#endif
};

/**
 * @brief 	Placement new override. 
 * @note	Some platforms might have global placement new definition, such as STL, MFC.
 */
#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_) && !defined(__PLACEMENT_NEW_INLINE) && !defined(_MFC_VER) && !defined(_NEW)
	#define __PLACEMENT_NEW_INLINE

	inline void* operator new(size_t size, void* pos)
	{
		return pos;
	}

	inline void operator delete(void* ptr, void* pos)
	{
	}
#endif //__PLACEMENT_NEW_INLINE

#endif //__cplusplus

//<<<+++OPENSOURCE_MUST_END
#else
//<<<+++OPENSOURCE_MUST_BEGIN LIC==GOOGLE
	#ifdef __cplusplus
	extern "C" {
	#endif
		#define FX_Alloc(type, size)						(type*)malloc(sizeof(type) * (size))
		#if _FXM_PLATFORM_ == _FXM_PLATFORM_WINDOWS_
			#define FX_AlignedAlloc(type, size, align)		(type*)_aligned_malloc(sizeof(type) * (size), align)
		#else
			#define FX_AlignedAlloc(type, size, align)		(type*)memalign(align, sizeof(type) * (size))
		#endif
		#define FX_Realloc(type, ptr, size)					(type*)realloc(ptr, sizeof(type) * (size))
		#define FX_AllocNL(type, size)						FX_Alloc(type, size)
		#define FX_ReallocNL(type, ptr, size)				FX_Realloc(type, ptr, size)
		#define FX_Free(ptr)								free(ptr)

		void*	FXMEM_DefaultAlloc(size_t byte_size, int flags);
		void*	FXMEM_DefaultRealloc(void* pointer, size_t new_size, int flags);
		void	FXMEM_DefaultFree(void* pointer, int flags);
	#ifdef __cplusplus
	}
	#endif

	#ifdef __cplusplus
	class CFX_Object
	{
	public:
		void*			operator new (size_t size, FX_LPCSTR file, int line)	{return malloc(size);}
		void			operator delete (void* p, FX_LPCSTR file, int line)		{free(p);}

		void*			operator new (size_t size)								{return malloc(size);}
		void			operator delete (void* p)								{free(p);}

		void*			operator new[] (size_t size, FX_LPCSTR file, int line)	{return malloc(size);}
		void			operator delete[] (void* p, FX_LPCSTR file, int line)	{free(p);}

		void*			operator new[] (size_t size)							{return malloc(size);}
		void			operator delete[] (void* p)								{free(p);}

		void*			operator new (size_t, void* buf)						{return buf;}
		void			operator delete (void*, void*)							{}
	};
	#endif //__cplusplus
//<<<+++OPENSOURCE_MUST_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
#ifdef __cplusplus

#if defined(_DEBUG)
	#define FX_NEW new(__FILE__, __LINE__)
#else
	/**
	 * @brief FPDFAPI applications should use the FX_NEW macro in place of "new" operator.
	 * @hideinitializer
	 */
	#define FX_NEW new
#endif
//<<<+++OPENSOURCE_MUST_END

#ifndef _FPDFAPI_MINI_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** @brief Vector allocator. Some platform doesn't provide clean vector allocator (like ADS). */
	#define FX_NEW_VECTOR(Pointer, Class, Count) Pointer = FX_NEW Class[Count]
	/** @brief Vector destroyer. */
	#define FX_DELETE_VECTOR(Pointer, Class, Count) delete[] Pointer
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	#define FX_NEW_VECTOR(Pointer, Class, Count) \
		{ \
			Pointer = FX_Alloc(Class, Count); \
			if (Pointer) { \
				for (int i = 0; i < (Count); i ++) new (Pointer + i) Class; \
			} \
		}
	#define FX_DELETE_VECTOR(Pointer, Class, Count) \
		{ \
			for (int i = 0; i < (Count); i ++) Pointer[i].~Class(); \
			FX_Free(Pointer); \
		}
	//<<<+++OPENSOURCE_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
/**
 * @brief Destructable objects: you can always safely delete an object derived from this class,
 * using its base class pointer.
 */
class CFX_DestructObject : public CFX_Object
{
public:
	/** virtual destructor */
	virtual ~CFX_DestructObject() {}
};
//<<<+++OPENSOURCE_MUST_END
#endif //__cplusplus

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Foxit allocator interface.
 */
typedef struct _IFX_Allocator
{
	/**
	 * A pointer type to a debug-mode allocation function.
	 *
	 * The function prototype is:
	 *		void* AllocDebug(IFX_Allocator* pAllocator, size_t size, FX_LPCSTR filename, int line);
	 * @param[in] pAllocator	A pointer to a IFX_Allocator object.
	 * @param[in] size			The size in bytes to allocate.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 * @return Address of new memory block.
	 */
	void*	(*m_AllocDebug)(struct _IFX_Allocator* pAllocator, size_t size, FX_LPCSTR file, int line);
	/**
	 * A pointer type to an allocation function.
	 *
	 * The function prototype is:
	 *		void* Alloc(IFX_Allocator* pAllocator, size_t size);
	 * @param[in] pAllocator	A pointer to a IFX_Allocator object.
	 * @param[in] size			The size in bytes to allocate.
	 * @return Address of new memory block.
	 */
	void*	(*m_Alloc)(struct _IFX_Allocator* pAllocator, size_t size);
	/**
	 * A pointer type to a debug-mode re-allocation function.
	 *
	 * The function prototype is:
	 *		void* ReallocDebug(IFX_Allocator* pAllocator, void* p, size_t size, FX_LPCSTR filename, int line);
	 * @param[in] pAllocator	A pointer to a IFX_Allocator object.
	 * @param[in] p				Pointer to reallocate.
	 * @param[in] size			The new size in bytes to reallocate.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 * @return Address of new pointer.
	 */
	void*	(*m_ReallocDebug)(struct _IFX_Allocator* pAllocator, void* p, size_t size, FX_LPCSTR file, int line);
	/**
	 * A pointer type to a re-allocation function.
	 *
	 * The function prototype is:
	 *		void* Realloc(IFX_Allocator* pAllocator, void* p, size_t size);
	 * @param[in] pAllocator	A pointer to a IFX_Allocator object.
	 * @param[in] p				Pointer to reallocate.
	 * @param[in] size			The new size in bytes to reallocate.
	 * @return Address of new pointer.
	 */
	void*	(*m_Realloc)(struct _IFX_Allocator* pAllocator, void* p, size_t size);
	/**
	 * A pointer type to a free function.
	 *
	 * The function prototype is:
	 *		void free(IFX_Allocator* pAllocator, void* p);
	 * @param[in] pAllocator	A pointer to a IFX_Allocator object.
	 * @param[in] p				Address of a memory block.
	 */
	void	(*m_Free)(struct _IFX_Allocator* pAllocator, void* p);
} IFX_Allocator;

/**
 * Get default allocator used by the library.
 *
 * @return The default IFX_Allocator pointer.
 */
IFX_Allocator* FXMEM_GetDefAllocator();

#ifdef __cplusplus
}
#endif

#ifdef _DEBUG
	/** Debug-mode allocation on an allocator. */
	#define FX_Allocator_Alloc(fxAllocator, type, size) \
		((fxAllocator) ? (type*)(fxAllocator)->m_AllocDebug((fxAllocator), (size) * sizeof(type), __FILE__, __LINE__) : (FX_Alloc(type, size)))
	/** Debug-mode re-allocation on an allocator. */
	#define FX_Allocator_Realloc(fxAllocator, type, ptr, new_size) \
		((fxAllocator) ? (type*)(fxAllocator)->m_ReallocDebug((fxAllocator), (ptr), (new_size) * sizeof(type), __FILE__, __LINE__) : (FX_Realloc(type, ptr, new_size)))
#else
	/** Release-mode allocation on an allocator. */
	#define FX_Allocator_Alloc(fxAllocator, type, size) \
		((fxAllocator) ? (type*)(fxAllocator)->m_Alloc((fxAllocator), (size) * sizeof(type)) : (FX_Alloc(type, size)))
	/** Release-mode re-allocation on an allocator. */
	#define FX_Allocator_Realloc(fxAllocator, type, ptr, new_size) \
		((fxAllocator) ? (type*)(fxAllocator)->m_Realloc((fxAllocator), (ptr), (new_size) * sizeof(type)) : (FX_Realloc(type, ptr, new_size)))
#endif
/** Free memory block on an allocator. */
#define FX_Allocator_Free(fxAllocator, ptr) \
		((fxAllocator) ? (fxAllocator)->m_Free((fxAllocator), (ptr)) : (FX_Free(ptr)))
//<<<+++OPENSOURCE_MUST_END
#endif
#ifdef __cplusplus

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
/** @brief 	Placement new override with ::IFX_Allocator. */
inline void* operator new(size_t size, IFX_Allocator* fxAllocator)
{
	return (void*)FX_Allocator_Alloc(fxAllocator, FX_BYTE, size);
}

inline void operator delete(void* ptr, IFX_Allocator* fxAllocator)
{
}

/** Macro for new operator on an allocator. */
#define FX_NewAtAllocator(fxAllocator) \
	::new(fxAllocator)
/** Macro for delete operator on an allocator. */
#define FX_DeleteAtAllocator(pointer, fxAllocator, __class__) \
	(pointer)->~__class__(); \
	FX_Allocator_Free(fxAllocator, pointer)

/**
 * @brief CFX_AllocObject class uses specific memory allocator to allocate and free memory.
 * All pAllocator parameter can be NULL, in this case the system default allocator is used 
 * (then it will be same as CFX_Object).
 */
class CFX_AllocObject
{
public:
	/**
	 * new operator for debug mode.
	 *
	 * @param[in] size			The size in bytes to allocate.
	 * @param[in] pAllocator	The Allocator used to allocate memory.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 * @return Address of a new memory block.
	 */
	void*			operator new (size_t size, IFX_Allocator* pAllocator, FX_LPCSTR file, int line);
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator for debug mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 * @param[in] pAllocator	The Allocator used to free memory.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 */
	void			operator delete (void* p, IFX_Allocator* pAllocator, FX_LPCSTR file, int line);
#endif

	/**
	 * new operator for release mode.
	 *
	 * @param[in] size			The size in bytes to allocate.
	 * @param[in] pAllocator	The Allocator used to allocate memory.
	 * @return Address of a new memory block.
	 */
	void*			operator new (size_t size, IFX_Allocator* pAllocator);
	/**
	 * delete operator for release mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 */
	void			operator delete (void* p);
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator for release mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 * @param[in] pAllocator	The Allocator used to free memory.
	 */
	void			operator delete (void* p, IFX_Allocator* pAllocator);
#endif

	/**
	 * placement new operator.
	 */
	void*			operator new (size_t, void* buf) { return buf; }
#ifndef _FX_NO_EXCEPTION_
	/**
	 * placement delete operator.
	 */
	void			operator delete (void*, void*) {}
#endif

	/**
	 * Gets the Allocator pointer.
	 * 
	 * @return A pointer to a IFX_Allocator object. 
	 */
	IFX_Allocator*	GetAllocator() const { return m_pAllocator; }

private:	/* all vector operators are disabled */
	/**
	 * new operator of vector for debug mode.
	 *
	 * @param[in] size			The size in bytes to allocate.
	 * @param[in] pAllocator	The Allocator used to allocate memory.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 * @return Address of a new memory block.
	 */
	void*			operator new[] (size_t size, IFX_Allocator* pAllocator, FX_LPCSTR file, int line) { return operator new(size, pAllocator, file, line); }
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator of vector for debug mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 * @param[in] pAllocator	The Allocator used to free memory.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 */
	void			operator delete[] (void* p, IFX_Allocator* pAllocator, FX_LPCSTR file, int line) {}
#endif

	/**
	 * new operator of vector for non-debug mode.
	 *
	 * @param[in] size			The size in bytes to allocate.
	 * @param[in] pAllocator	The Allocator used to allocate memory.
	 * @return Address of a new memory block.
	 */
	void*			operator new[] (size_t size, IFX_Allocator* pAllocator) { return operator new(size, pAllocator); }
	/**
	 * delete operator of vector for non-debug mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 */
	void			operator delete[] (void* p) {}
#ifndef _FX_NO_EXCEPTION_
	/**
	 * delete operator of vector for non-debug mode.
	 *
	 * @param[in] p				The Address of a memory block to be deleted.
	 * @param[in] pAllocator	The Allocator used to free memory.
	 */
	void			operator delete[] (void* p, IFX_Allocator* pAllocator) {}
#endif

protected:
	/**
	 * The memory allocator.
	 */
	IFX_Allocator*	m_pAllocator;
};

#if defined(_DEBUG)
	#define FX_NEWAT(pAllocator) new(pAllocator, __FILE__, __LINE__)
#else
	/**
	 * @brief Foxit application should use FX_NEWAT macro when new a CFX_AllocObject derived object.
	 * @hideinitializer
	 */
	#define FX_NEWAT(pAllocator) new(pAllocator)
#endif
#endif
//<<<+++OPENSOURCE_MUST_END

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
//////////////////////////////////////////////////////////////////////
//Cocurrency controls
//////////////////////////////////////////////////////////////////////
#if (_FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_) && !defined(_FX_NO_WINDOWS_)
	// We enable multi-threading by default on Windows systems. On other systems, MT needs to be enabled by compilation macro
	#define _FPDFAPI_MT_
#endif

#ifdef _FPDFAPI_MT_
	/**
	 * @brief Lock object class.
	 */
	class CFX_LockObject : public CFX_Object
	{
	public:
		/** Construct a lock object. */
		CFX_LockObject() {FX_InitializeCriticalSection(&m_Lock);}
		/** Destruct a lock object. */
		~CFX_LockObject() {FX_DeleteCriticalSection(&m_Lock);}

		/** Try to lock. For separating control. */
		FX_BOOL		TryLock()	{return FX_TryEnterCriticalSection(&m_Lock);}
		/** Lock. For separating control. */
		void		Lock()		{FX_EnterCriticalSection(&m_Lock);}
		/** Unlock. For separating control. */
		void		Unlock()	{FX_LeaveCriticalSection(&m_Lock);}

	protected:
		/** Critical section. */
		FX_CRITICAL_SECTION		m_Lock;
		friend class CFX_CSLock;
	};

	/**
	 * @brief Lock operation class.
	 */
	class CFX_CSLock
	{
	public:
		/** Default constructor. */
		CFX_CSLock() : m_pCS(NULL) {}
		/** Construct a lock operation with a critical section. */
		CFX_CSLock(FX_CRITICAL_SECTION* pCS) : m_pCS(pCS) {if (m_pCS) FX_EnterCriticalSection(m_pCS);}
		/** Construct a Lock operation. */
		CFX_CSLock(CFX_LockObject* pObj) {m_pCS = &pObj->m_Lock; FX_EnterCriticalSection(m_pCS);}
		/** Destruct a lock operation. */
		~CFX_CSLock() {if (m_pCS) FX_LeaveCriticalSection(m_pCS);}

		/** Critical Section. */
		FX_CRITICAL_SECTION*	m_pCS;
	};

	/** @brief A macro defines a lock operation with this pointer. */
	#define FXMT_CSLOCK_THIS					CFX_CSLock _fx_lock((CFX_LockObject*)this)
	/** @brief A macro defines a lock operation with a lock object. */
	#define FXMT_CSLOCK_OBJ(lock)				CFX_CSLock _fx_lock((CFX_LockObject*)lock)
	/** @brief A macro defines a named lock operation with a lock object. */
	#define FXMT_CSLOCK_DEFINEOBJ(csLock, lock) CFX_CSLock csLock((CFX_LockObject*)lock)

	/** @brief A macro defines a lock object. */
	#define FXMT_LOCKOBJECT_DEFINE(lockObj)		CFX_LockObject lockObj
	/** @brief A macro tries to lock. */
	#define FXMT_LOCKOBJECT_TRYLOCK(lockObj)	(lockObj)->TryLock()
	/** @brief A macro tries to lock with if. */
	#define FXMT_LOCKOBJECT_TRYLOCK_IF(lockObj)	if ((lockObj)->TryLock())
	/** @brief A macro locks. */
	#define FXMT_LOCKOBJECT_LOCK(lockObj)		(lockObj)->Lock()
	/** @brief A macro unlocks. */
	#define FXMT_LOCKOBJECT_UNLOCK(lockObj)		(lockObj)->Unlock()
#else //!_FPDFAPI_MT_
	class CFX_LockObject : public CFX_Object {};
	#define FXMT_CSLOCK_THIS
	#define FXMT_CSLOCK_OBJ(lock)
	#define FXMT_CSLOCK_DEFINEOBJ(csLock, lock)

	#define FXMT_LOCKOBJECT_DEFINE(lockObj)
	#define FXMT_LOCKOBJECT_TRYLOCK(lockObj)
	#define FXMT_LOCKOBJECT_TRYLOCK_IF(lockObj)	if (1)
	#define FXMT_LOCKOBJECT_LOCK(lockObj)
	#define FXMT_LOCKOBJECT_UNLOCK(lockObj)
#endif
//<<<+++OPENSOURCE_MUST_END
#endif

/**
 * @brief Memory Allocator for Build-Readonly applications, which only grow the memory consumption,
 * then free them all at once. This can be very useful when consolidating small memory pieces 
 * together especially on embedded platforms. Also because there is no need to keep track of 
 * block availability, there is no allocation overhead.
 */
#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CFX_GrowOnlyPool : public IFX_Allocator, public CFX_Object
//<<<+++OPENSOURCE_END
#else
//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
class CFX_GrowOnlyPool : public CFX_Object
//<<<+++OPENSOURCE_END
#endif
{
public:
	/**
	 * A Constructor.
	 *
	 * @param[in] pAllocator	the memory allocator pointer. Can be NULL for FXCRT default allocator.
	 * @param[in] trunk_size	the size of the memory consumption. default trunk size is 16K.
	 */
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CFX_GrowOnlyPool(IFX_Allocator* pAllocator = NULL, size_t trunk_size = 16384);
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CFX_GrowOnlyPool(size_t trunk_size = 16384);
	//<<<+++OPENSOURCE_END
#endif
	/**
	 * A Destructor.
	 */
	~CFX_GrowOnlyPool();

#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Change the allocator. The underlying allocator can only be changed before anything allocated from the pool.
	 *
	 * @param[in] pAllocator	an IFX_Allocator pointer.
	 */
	void	SetAllocator(IFX_Allocator* pAllocator);
	//<<<+++OPENSOURCE_END
#endif

	/**
	 * Change the trunk size.
	 *
	 * @param[in] trunk_size	new trunk size to change.
	 */
	void	SetTrunkSize(size_t trunk_size) { m_TrunkSize = trunk_size; }

	/**
	 * The debug-mode allocation function.
	 * 
	 * @param[in] size			the size in bytes to allocate.
	 * @param[in] file			The name of the current source file.
	 * @param[in] line			The line number in the current source file.
	 * @return Address of new memory block.
	*/
	void*	AllocDebug(size_t size, FX_LPCSTR file, int line) { return Alloc(size); }
	/**
	 * The allocation function.
	 *
	 * @param[in] size			The size in bytes to allocate.
	 * @return Address of new memory block.
	 */
	void*	Alloc(size_t size);
	/**
	 * The debug-mode re-allocation function.
	 *
	 * @remark	Do not call this function.
	*/
	void*	ReallocDebug(void* p, size_t new_size, FX_LPCSTR file, int line) { return NULL; }
	/**
	 * The re-allocation function.
	 *
	 * @remark	Do not call this function.
	 */
	void*	Realloc(void* p, size_t new_size) { return NULL; }
	/**
	 * The free function.
	 */
	void	Free(void*) {}

	/**
	 * Free all the memory.
	 */
	void	FreeAll();

private:
	/** trunk size. */
	size_t	m_TrunkSize;
	/** pointer to the first trunk. */  
	void*	m_pFirstTrunk;
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** memory allocator. */
	IFX_Allocator*	m_pAllocator;
		/** critical section used for synchronization. */
		FX_CRITICAL_SECTION	m_Lock;
	//<<<+++OPENSOURCE_END
#endif
};

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT

//*****************************************************************************
//* Cache management (Testing mode currently)
//*****************************************************************************
/**
 * @brief Cache consumer. One module can create one or more(if necessary) cache object.
 */
class IFX_Cache
{
public:
	/** Destroy the current instance. */
	virtual void		Release() = 0;

	/** Allocate a memory buffer and return the pointer. */
	virtual void*		Alloc(size_t size)		{return NULL;}
	virtual FX_BOOL		Lock(void* pBuffer)		{return FALSE;}
	virtual FX_BOOL		Unlock(void* pBuffer)	{return FALSE;}

	virtual void		Purge() = 0;
	virtual void		ClearAll() = 0;
};

IFX_Cache*	FXMEM_Cache_CreateDef(IFX_Allocator* pAllocator = NULL, size_t nChunkSize = 1024 * 64, size_t nMaxSize = 1024 * 1024 * 2);
FX_BOOL		FXMEM_Cache_Register(FXMEM_FoxitMgr* pFoxitMgr, IFX_Cache* pCache);
FX_BOOL		FXMEM_Cache_Unregister(FXMEM_FoxitMgr* pFoxitMgr, IFX_Cache* pCache);
void		FXMEM_Cache_Purge(FXMEM_FoxitMgr* pFoxitMgr);
void		FXMEM_Cache_ClearAll(FXMEM_FoxitMgr* pFoxitMgr);

#ifdef PDF_USE_PAGECACHE_
#include <new>

extern const FX_BYTE ZeroLeadPos[256];

template <size_t blockSize, size_t alignSize = 16>
class CFX_Cache_FixedSizeTemplate_FixedPage
{
public:
	static size_t CalculateSize(size_t blockNum) {
		size_t startSize = (sizeof(CFX_Cache_FixedSizeTemplate_FixedPage) + (blockNum + 7) / 8 + alignSize - 1) / alignSize * alignSize;
		return startSize + blockSize * blockNum;
	}

	void Initialize(size_t  blockNum)
	{
		m_nAvailCount = blockNum;

		m_nBlockNum	  = blockNum;

		FXSYS_memset32(m_BusyMap, 0, (blockNum + 7) / 8);
	}

	FX_BOOL		HasFreeBlock() const
	{
		return (FX_BOOL)m_nAvailCount;
	}

	FX_LPVOID	Alloc(size_t size)
	{
		FXSYS_assert(m_nAvailCount);

		FX_LPDWORD pFind = (FX_LPDWORD)m_BusyMap;
		size_t i = 0;
		size_t c = (m_nBlockNum + 7) / 8 / sizeof(FX_DWORD);
		while (i < c && pFind[i] == ((FX_DWORD)-1)) i ++;
		i *= sizeof(FX_DWORD);
		while (m_BusyMap[i] == 0xFF) i ++;

		size_t pos = ZeroLeadPos[m_BusyMap[i]];
		m_BusyMap[i] |= 1 << (7 - pos);
		m_nAvailCount --;

		size_t startSize = (sizeof(CFX_Cache_FixedSizeTemplate_FixedPage) + (m_nBlockNum + 7) / 8 + alignSize - 1) / alignSize * alignSize;

		return (FX_LPBYTE)this + startSize + (i * 8 + pos) * blockSize;
	}

	void		Free(FX_LPVOID p)
	{
		FXSYS_memset32(p, 0, blockSize);

		size_t startSize = (sizeof(CFX_Cache_FixedSizeTemplate_FixedPage) + (m_nBlockNum + 7) / 8 + alignSize - 1) / alignSize * alignSize;
		size_t pos = (((FX_LPBYTE)p - (FX_LPBYTE)this) - startSize) / blockSize;

		m_BusyMap[pos / 8] &= ~(1 << (7 - (pos % 8)));
		m_nAvailCount ++;
	}

	volatile size_t	m_nAvailCount;
	volatile size_t m_nBlockNum;
	FX_BYTE			m_BusyMap[1];
};

template <class ObjClass, size_t ObjSize = sizeof(ObjClass)>
class CFX_Cache_FixedSizeTemplate
{
protected:
	struct FIXEDSIZETEMPLATE_CHUNK
	{
		typedef CFX_Cache_FixedSizeTemplate_FixedPage<ObjSize> ChunkType;

		struct FIXEDSIZETEMPLATE_CHUNK* pNextChunk;
		ChunkType ChunkData;
	};

	size_t						m_nBlockCount;
	FIXEDSIZETEMPLATE_CHUNK* m_pAvailTopChunk;
	FIXEDSIZETEMPLATE_CHUNK* m_pFullTopChunk;

public:
	CFX_Cache_FixedSizeTemplate() : m_pAvailTopChunk(NULL), m_pFullTopChunk(NULL), m_nBlockCount(32 * 32 * 4) {}
	~CFX_Cache_FixedSizeTemplate() { ASSERT(m_pAvailTopChunk == NULL && m_pFullTopChunk == NULL); }

	inline ObjClass* Construct(IFX_Allocator* pAllocator = NULL) {
		ObjClass* pRetValue = NULL;
		Alloc(pRetValue, pAllocator);
		if(pRetValue) {
			::new(pRetValue) ObjClass;
		}
		return pRetValue;
	}

#ifdef _DEBUG
	inline FX_BOOL Own(ObjClass* pObject) {
		FIXEDSIZETEMPLATE_CHUNK* pChunk = FindChunk(pObject);
		if(pChunk) {
			return TRUE;
		}
		return FALSE;
	}
#endif

	inline void Recycle(ObjClass* pObject) {
		FIXEDSIZETEMPLATE_CHUNK* pPrevious = NULL;
		FIXEDSIZETEMPLATE_CHUNK* pChunk = FindChunk2(pObject, &pPrevious);
		if(pChunk) {
			if(pChunk->ChunkData.m_nAvailCount == pChunk->ChunkData.m_nBlockNum) {
				// within full stack.
				if(pPrevious) {
					pPrevious->pNextChunk = pChunk->pNextChunk;
				} else {
					m_pFullTopChunk = pChunk->pNextChunk;
				}
				pChunk->pNextChunk = m_pAvailTopChunk;
				m_pAvailTopChunk = pChunk;				
			}
			pChunk->ChunkData.Free(pObject);
		} 
	}

	void SetBlockCount(size_t nBlockCount) {
		m_nBlockCount = nBlockCount;
	}

	void Alloc(ObjClass*& pObject, IFX_Allocator* pAllocator = NULL) {
		FIXEDSIZETEMPLATE_CHUNK* pCurChunk = m_pAvailTopChunk;
		if (!pCurChunk) {
			pCurChunk = (FIXEDSIZETEMPLATE_CHUNK*)
				FX_Allocator_Alloc(pAllocator, FX_BYTE, sizeof(FIXEDSIZETEMPLATE_CHUNK) - sizeof(typename FIXEDSIZETEMPLATE_CHUNK::ChunkType) + FIXEDSIZETEMPLATE_CHUNK::ChunkType::CalculateSize(m_nBlockCount));
			if(!pCurChunk) {
				pObject = NULL; return;
			}

			pCurChunk->ChunkData.Initialize(m_nBlockCount);
			pCurChunk->pNextChunk = m_pAvailTopChunk;
			m_pAvailTopChunk = pCurChunk;
		}
		pObject = (ObjClass*)pCurChunk->ChunkData.Alloc(sizeof(ObjClass));
		if(!pCurChunk->ChunkData.HasFreeBlock()) {
			m_pAvailTopChunk = pCurChunk->pNextChunk;

			pCurChunk->pNextChunk = m_pFullTopChunk;
			m_pFullTopChunk = pCurChunk;
		}
	}

	FIXEDSIZETEMPLATE_CHUNK* FindChunk(ObjClass* pObject) {
		if (!pObject) return NULL;

		FIXEDSIZETEMPLATE_CHUNK* pChunk;
		pChunk = m_pAvailTopChunk;
		while(pChunk) {
			if ((FX_LPBYTE)pObject >  (FX_LPBYTE)&pChunk->ChunkData && 
				(FX_LPBYTE)pObject <= (FX_LPBYTE)&pChunk->ChunkData + sizeof(FIXEDSIZETEMPLATE_CHUNK) - sizeof(typename FIXEDSIZETEMPLATE_CHUNK::ChunkType) + pChunk->ChunkData.CalculateSize(pChunk->ChunkData.m_nBlockNum)) {

					return pChunk;
			}
			pChunk = pChunk->pNextChunk;
		}
		pChunk = m_pFullTopChunk;
		while(pChunk) {
			if ((FX_LPBYTE)pObject >  (FX_LPBYTE)&pChunk->ChunkData && 
				(FX_LPBYTE)pObject <= (FX_LPBYTE)&pChunk->ChunkData + sizeof(FIXEDSIZETEMPLATE_CHUNK) - sizeof(typename FIXEDSIZETEMPLATE_CHUNK::ChunkType) + pChunk->ChunkData.CalculateSize(pChunk->ChunkData.m_nBlockNum)) {

					return pChunk;
			}
			pChunk = pChunk->pNextChunk;
		}
		return NULL;
	}

	FIXEDSIZETEMPLATE_CHUNK* FindChunk2(ObjClass* pObject, FIXEDSIZETEMPLATE_CHUNK** pPreviousChunk) {
		if (!pObject) return NULL;

		FIXEDSIZETEMPLATE_CHUNK *pPrevious, *pChunk;
		pPrevious = NULL;
		pChunk = m_pAvailTopChunk;
		while(pChunk) {
			if ((FX_LPBYTE)pObject >  (FX_LPBYTE)&pChunk->ChunkData && 
				(FX_LPBYTE)pObject <= (FX_LPBYTE)&pChunk->ChunkData + sizeof(FIXEDSIZETEMPLATE_CHUNK) - sizeof(typename FIXEDSIZETEMPLATE_CHUNK::ChunkType) + pChunk->ChunkData.CalculateSize(pChunk->ChunkData.m_nBlockNum)) {
					if(pPreviousChunk) *pPreviousChunk = pPrevious;
					return pChunk;
			}
			pPrevious = pChunk;
			pChunk = pChunk->pNextChunk;
		}

		pPrevious = NULL;
		pChunk = m_pFullTopChunk;
		while(pChunk) {
			if ((FX_LPBYTE)pObject >  (FX_LPBYTE)&pChunk->ChunkData && 
				(FX_LPBYTE)pObject <= (FX_LPBYTE)&pChunk->ChunkData + sizeof(FIXEDSIZETEMPLATE_CHUNK) - sizeof(typename FIXEDSIZETEMPLATE_CHUNK::ChunkType) + pChunk->ChunkData.CalculateSize(pChunk->ChunkData.m_nBlockNum)) {
					if(pPreviousChunk) *pPreviousChunk = pPrevious;
					return pChunk;
			}
			pPrevious = pChunk;
			pChunk = pChunk->pNextChunk;
		}

		return NULL;
	}

	void CollectGarbage(IFX_Allocator* pAllocator = NULL) {
		FIXEDSIZETEMPLATE_CHUNK *pLastChunk = NULL, *pCurChunk = m_pAvailTopChunk;
		while(pCurChunk) {
			while(pCurChunk && pCurChunk->ChunkData.m_nAvailCount == pCurChunk->ChunkData.m_nBlockNum) {
				if (pLastChunk) {
					pLastChunk->pNextChunk = pCurChunk->pNextChunk;
					FX_Allocator_Free(pAllocator, pCurChunk);
					pCurChunk = pLastChunk->pNextChunk;
				} else {
					m_pAvailTopChunk = pCurChunk->pNextChunk;
					FX_Allocator_Free(pAllocator, pCurChunk);
					pCurChunk = m_pAvailTopChunk;
				}
			}
			if(!pCurChunk) break;

			pLastChunk = pCurChunk;
			pCurChunk  = pCurChunk->pNextChunk;
		}
	}

	void ReleaseMemory(IFX_Allocator* pAllocator = NULL) {
		while(m_pAvailTopChunk) {
			FIXEDSIZETEMPLATE_CHUNK* pNextChunk = m_pAvailTopChunk->pNextChunk;
			FX_Allocator_Free(pAllocator, m_pAvailTopChunk);
			m_pAvailTopChunk = pNextChunk;
		}
		while(m_pFullTopChunk) {
			FIXEDSIZETEMPLATE_CHUNK* pNextChunk = m_pFullTopChunk->pNextChunk;
			FX_Allocator_Free(pAllocator, m_pFullTopChunk);
			m_pFullTopChunk = pNextChunk;
		}
	}
};

class CFXMEM_Page;

class CFX_Cache_Reusable
{
protected:
	struct REUSABLE_CHUNK;

	REUSABLE_CHUNK*				m_pTopChunk;
	size_t						m_nChunkBufferSize;

public:
	CFX_Cache_Reusable() : m_pTopChunk(NULL), m_nChunkBufferSize(32 * 32 * 4 * 64) {}
	~CFX_Cache_Reusable() { ASSERT(m_pTopChunk == NULL); }

#ifdef _DEBUG
	inline FX_BOOL Own(FX_LPVOID pData) {
		REUSABLE_CHUNK* pChunk = FindChunk(pData);
		if(pChunk) {
			return TRUE;
		}
		return FALSE;
	}
#endif

	void Recycle(FX_LPVOID pData);

	void* Alloc(size_t size, IFX_Allocator* pAllocator = NULL);

	REUSABLE_CHUNK* FindChunk(FX_LPVOID pData);

	void SetChunkBufferSize(size_t nBufferSize) {
		m_nChunkBufferSize = nBufferSize;
	}

	void CollectGarbage(IFX_Allocator* pAllocator = NULL);

	void ReleaseMemory(IFX_Allocator* pAllocator = NULL);
};

class CFX_Cache_GrowOnly
{
public:
	FX_LPBYTE			m_pCurrentChunk;
	size_t				m_nChunkSize;
	size_t				m_nCurrentOffset;

public:
	CFX_Cache_GrowOnly() : m_pCurrentChunk(NULL), m_nChunkSize(64 * 16 * 32), m_nCurrentOffset(0) {}
	~CFX_Cache_GrowOnly() { ASSERT(m_pCurrentChunk == NULL); }

	void* Alloc(size_t size, IFX_Allocator* pAllocator = NULL) {
		if (!size) size++; //ensure each successful allocation return different results.
		FX_LPVOID lpRetValue = NULL;
		if (sizeof(FX_LPVOID) + size >= m_nChunkSize) {
			FX_LPBYTE pBuffer = FX_Allocator_Alloc(pAllocator, FX_BYTE, sizeof(FX_LPVOID) + size);
			if (!pBuffer) return NULL;
			lpRetValue = pBuffer + sizeof(FX_LPVOID);
			if (m_pCurrentChunk) {
				*(FX_LPVOID*)pBuffer = *(FX_LPVOID*)m_pCurrentChunk;
				*(FX_LPVOID*)m_pCurrentChunk = pBuffer;
			} else {
				m_pCurrentChunk = pBuffer;
				m_nCurrentOffset = sizeof(FX_LPVOID) + size;
			}
		} else if (!m_pCurrentChunk || m_nCurrentOffset + size > m_nChunkSize) {
			FX_LPBYTE pBuffer = FX_Allocator_Alloc(pAllocator, FX_BYTE, m_nChunkSize);
			if (!pBuffer) return NULL;
			*(FX_LPVOID*)pBuffer = m_pCurrentChunk;
			lpRetValue = pBuffer + sizeof(FX_LPVOID);
			m_nCurrentOffset = sizeof(FX_LPVOID) + size;
			m_pCurrentChunk  = pBuffer;
		} else {
			lpRetValue = m_pCurrentChunk + m_nCurrentOffset;
			m_nCurrentOffset += size;
		}
		return lpRetValue;
	}

#ifdef _DEBUG
	FX_BOOL Own(FX_LPVOID pointer) {
		for (FX_LPBYTE pChunk = m_pCurrentChunk; pChunk; pChunk = *(FX_LPBYTE*)pChunk) {
			if((FX_LPBYTE)pointer >= pChunk + sizeof(FX_LPVOID) && (FX_LPBYTE)pointer < pChunk + m_nChunkSize)
				return TRUE;
		}
		return FALSE;
	}
#endif

	void ReleaseMemory(IFX_Allocator* pAllocator = NULL) {
		while (m_pCurrentChunk) {
			FX_LPBYTE pChunk = m_pCurrentChunk;
			m_pCurrentChunk = *(FX_LPBYTE*)pChunk;
			FX_Allocator_Free(pAllocator, pChunk);
		}
	}

	void SetChunkBufferSize(size_t nNewChunkSize) {
		if (m_pCurrentChunk && nNewChunkSize > m_nChunkSize)
			m_nCurrentOffset = nNewChunkSize; // do not use this chunk any more.
		m_nChunkSize = nNewChunkSize;
	}

	template <class ObjClass>
	inline ObjClass* Construct(IFX_Allocator* pAllocator = NULL, size_t nObjSize = sizeof(ObjClass)) {
		ObjClass* pRetValue = (ObjClass*)Alloc(nObjSize, pAllocator);
		if(pRetValue) {
			::new(pRetValue) ObjClass;
		}
		return pRetValue;
	}
};
#endif //PDF_USE_PAGECACHE_

//<<<+++OPENSOURCE_MUST_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
#endif //__cplusplus
//<<<+++OPENSOURCE_MUST_END

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT

#ifdef __cplusplus
extern "C" {
#endif

//*****************************************************************************
//* Fixed memory management
//*****************************************************************************
#define _FXMEM_NO64_
//#define	_FXMEM_LIT_

/** @brief Size of memory page, 64KB. */
#define FX_FIXEDMEM_PAGESIZE		(4096 * 16)
/** @brief Size of middle data block, 4KB. */
#define FX_FIXEDMEM_MIDBLOCKSIZE	(4096)

/** @brief Structure of fixed memory configuration. */
typedef struct _FX_MEMCONFIG
{
	/** @brief Initial number of memory pages for 8-bytes fixed data size. 1 for desktop platforms, 1 for limited memory environments. */
	size_t	nPageNum_Init8;
	/** @brief Initial number of memory pages for 16-bytes fixed data size. 8 for desktop platforms, 5 for limited memory environments. */
	size_t	nPageNum_Init16;
	/** @brief Initial number of memory pages for 32-bytes fixed data size. 24 for desktop platforms, 8 for limited memory environments. */
	size_t	nPageNum_Init32;
	#if !defined(_FXMEM_NO64_)
		size_t	nPageNum_Init64;
	#endif
	/** @brief More number of memory pages for 16-bytes fixed data size. 8 for desktop platforms, 4 for limited memory environments. */
	size_t	nPageNum_More16;
	/** @brief More number of memry pages for 32-bytes fixed data size. 24 for desktop platforms, 12 for limited memory environments. */
	size_t	nPageNum_More32;
	#if !defined(_FXMEM_NO64_)
		size_t	nPageNum_More64;
	#endif
	#if defined(_FXMEM_LIT_)
		size_t	nPageSize_Lit;
		size_t	nPageNum_InitLit;
		size_t	nPageNum_MoreLit;
		size_t	nPageNum_ReservedLit;
	#endif
	/** @brief Size of memory pages for middle data range (> 32-bytes & <= FX_FIXEDMEM_MIDBLOCKSIZE). 32 for desktop platforms, 8 for limited memory environments. */
	size_t	nPageSize_Mid;
	/** @brief Initial number of memory pages for middle data range. 2 for desktop platforms, 2 for limited memory environments. */
	size_t	nPageNum_InitMid;
	/** @brief More number of memory pages for middle data range. 4 for desktop platforms, 4 for limited memory environments. */
	size_t	nPageNum_MoreMid;
	/** @brief Minimum size of memory page for large data (> FX_FIXEDMEM_MIDBLOCKSIZE). 128 for desktop platforms, 32 for limited memory environments. */
	size_t	nPageSize_Large;
	/** @brief Minimum size of alone memory page for large data. 64 for desktop platforms, 64 for limited memory environments. */
	size_t	nPageSize_Alone;
}FX_MEMCONFIG;

/**
 * Set configuration of fixed memory.
 * This function is optional for desktop platforms,
 * and should be called at first to change default configuration
 * when start application before initialize fixed memory manager.
 *
 * @param[in] memConfig		A pointer to memory configuration.
 */
void	FXMEM_SetConfig(const FX_MEMCONFIG* memConfig);

/** @brief Fixed memory state. */
//#define _FX_MEMSTATE_
#if defined(_FX_MEMSTATE_)

	typedef struct _FX_MEMPAGESTATE_
	{
		size_t	nCurMemSize;
		size_t	nMinMemSize;
		size_t	nMaxMemSize;
		size_t	nCurAvailSize;
		size_t	nMinAvailSize;
		size_t	nMaxAvailSize;
		size_t	nCurUsedSize;
		size_t	nMinUsedSize;
		size_t	nMaxUsedSize;
		size_t	nCurUsedRate;
		size_t	nMinUsedRate;
		size_t	nMaxUsedRate;
		size_t	bValid;
	}FX_MEMPAGESTATE;
	typedef struct _FX_MEMINFO_
	{
		size_t			memBlockCount[64];
		FX_MEMPAGESTATE	pageState8;
		FX_MEMPAGESTATE	pageState16;
		FX_MEMPAGESTATE	pageState32;
		FX_MEMPAGESTATE	pageStateMid;
		FX_MEMPAGESTATE	pageStateLarge;
		FX_MEMPAGESTATE	totalState;
	}FX_MEMINFO;

	#define FX_MEMSTATE_RATEFRACTION	100000

	void			FX_MemState_MergeInfo(FX_MEMINFO *mi1, const FX_MEMINFO *mi2);
	FX_MEMINFO*		FX_MemState_GetInfo();
	void			FX_MemState_ResetInfo();

#endif //_FX_MEMSTATE_

#ifdef __cplusplus
}
#endif

//<<<+++OPENSOURCE_MUST_END
#endif

//<<<+++OPENSOURCE_MUST_BEGIN
#endif //_FX_MEMORY_H_
//<<<+++OPENSOURCE_MUST_END

/** @} */

//<<<+++OPENSOURCE_END
